/*
 * Copyright 2011 Katsunori Koyanagi
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package sweezy.core.utils
{
	import flash.system.Capabilities;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import sweezy.core.reflect.IProperty;
	import sweezy.core.reflect.IType;
	import sweezy.core.reflect.Reflection;

	public class Messages
	{

		private static var _messagesCache:Dictionary = new Dictionary();

		public static function getInstance(type:Class):Messages
		{
			if (type in _messagesCache)
			{
				return _messagesCache[type];
			}

			var messages:Messages = new type();
			_messagesCache[type] = messages;

			return messages;
		}

		private var _language:String;

		private var _messages:Object;

		public function Messages()
		{
			init()
		}

		public function format(key:String, ... args):String
		{
			return StringUtils.format(lookupString(key), args);
		}

		public function format2(key:String, args:Array = null):String
		{
			return StringUtils.format(lookupString(key), args);
		}

		public function get(key:String):String
		{
			return lookupString(key);
		}

		public function get language():String
		{
			return _language === null ? Capabilities.language : _language;
		}

		public function set language(value:String):void
		{
			if (value)
			{
				_language = value;
			}
			else
			{
				_language = null;
			}
		}

		private function init():void
		{
			_messages = {};

			var type:IType = Reflection.forInstance(this);
			var bytesArrayType:IType = Reflection.forClass(ByteArray);

			for each (var property:IProperty in type.properties)
			{
				if (!property.isVariable)
				{
					continue;
				}
				if (property.type.rawClass !== Class)
				{
					continue;
				}

				var propertyClass:Class = property.getValue(property.isStatic ? null : this);

				if (propertyClass === null)
				{
					continue;
				}

				var propertyType:IType = Reflection.forClass(propertyClass);
				var superType:IType = propertyType.superClass;
				if (superType === null)
				{
					continue;
				}
				if (!bytesArrayType.isAssignableFrom(superType))
				{
					continue;
				}

				register(property.name, propertyClass);
			}
		}

		private function lookupString(key:String):String
		{
			var messages:Object = _messages[language];
			var template:String = null;
			if (messages !== null)
			{
				template = messages[key];
			}

			if (template !== null)
			{
				return template;
			}

			for each (messages in _messages)
			{
				template = messages[key];
				if (template !== null)
				{
					return template;
				}
			}

			return "";
		}

		private function register(lang:String, MessageResource:Class):void
		{
			var messages:Object = _messages[lang];
			if (messages === null)
			{
				messages = _messages[lang] = {};
			}

			var text:String = new String(new MessageResource());
			for each (var token:String in text.split(/\n|\r/))
			{
				token = StringUtils.trim(token);
				if (token.length === 0)
				{
					continue;
				}
				if (token.indexOf("#") === 0)
				{
					continue;
				}

				var index:uint = token.indexOf("=");
				if (index === -1)
				{
					continue;
				}

				var name:String = StringUtils.trim(token.substring(0, index));
				var value:String = StringUtils.trim(token.substring(index + 1));
				messages[name] = value;
			}
		}
	}
}
